// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2017 Red Hat, Inc. <contact@redhat.com>
 *
 * Author: Adam C. Emerson <aemerson@redhat.com>
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 2.1, as published by the Free Software Foundation.  See file
 * COPYING.
 */

#ifndef COMMON_CEPH_ERROR_CODE
#define COMMON_CEPH_ERROR_CODE

#include <netdb.h>

#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"

namespace ceph
{
    // This is for error categories we define, so we can specify the
    // equivalent integral value at the point of definition.
    class converting_category : public boost::system::error_category
    {
    public:
        virtual int from_code(int code) const noexcept = 0;
    };

    const boost::system::error_category &ceph_category() noexcept;

    enum class errc
    {
        not_in_map = 1, // The requested item was not found in the map
        does_not_exist, // Item does not exist
        failure,        // An internal fault or inconsistency
        exists,         // Already exists
        limit_exceeded, // Attempting to use too much of something
        auth,           // May not be an auth failure. It could be that the
                        // preconditions to attempt auth failed.
        conflict,       // Conflict or precondition failure
    };
}

namespace boost::system
{
    template <>
    struct is_error_condition_enum<::ceph::errc>
    {
        static const bool value = true;
    };
    template <>
    struct is_error_code_enum<::ceph::errc>
    {
        static const bool value = false;
    };
}

namespace ceph
{
    //  explicit conversion:
    inline boost::system::error_code make_error_code(errc e) noexcept
    {
        return {static_cast<int>(e), ceph_category()};
    }

    // implicit conversion:
    inline boost::system::error_condition make_error_condition(errc e) noexcept
    {
        return {static_cast<int>(e), ceph_category()};
    }

    [[nodiscard]] boost::system::error_code to_error_code(int ret) noexcept;
    [[nodiscard]] int from_error_code(boost::system::error_code e) noexcept;
}
#pragma GCC diagnostic pop
#pragma clang diagnostic pop

// Moved here from buffer.h so librados doesn't gain a dependency on
// Boost.System

namespace ceph::buffer
{
    inline namespace v15_2_0
    {
        const boost::system::error_category &buffer_category() noexcept;
        enum class errc
        {
            bad_alloc = 1,
            end_of_buffer,
            malformed_input
        };
    }
}

namespace boost::system
{
    template <>
    struct is_error_code_enum<::ceph::buffer::errc>
    {
        static const bool value = true;
    };

    template <>
    struct is_error_condition_enum<::ceph::buffer::errc>
    {
        static const bool value = false;
    };
}

namespace ceph::buffer
{
    inline namespace v15_2_0
    {
        // implicit conversion:
        inline boost::system::error_code make_error_code(errc e) noexcept
        {
            return {static_cast<int>(e), buffer_category()};
        }

        // explicit conversion:
        inline boost::system::error_condition
        make_error_condition(errc e) noexcept
        {
            return {static_cast<int>(e), buffer_category()};
        }

        struct error : boost::system::system_error
        {
            using system_error::system_error;
        };

        struct bad_alloc : public error
        {
            bad_alloc() : error(errc::bad_alloc) {}
            bad_alloc(const char *what_arg) : error(errc::bad_alloc, what_arg) {}
            bad_alloc(const std::string &what_arg) : error(errc::bad_alloc, what_arg) {}
        };
        struct end_of_buffer : public error
        {
            end_of_buffer() : error(errc::end_of_buffer) {}
            end_of_buffer(const char *what_arg) : error(errc::end_of_buffer, what_arg) {}
            end_of_buffer(const std::string &what_arg)
                : error(errc::end_of_buffer, what_arg) {}
        };

        struct malformed_input : public error
        {
            malformed_input() : error(errc::malformed_input) {}
            malformed_input(const char *what_arg)
                : error(errc::malformed_input, what_arg) {}
            malformed_input(const std::string &what_arg)
                : error(errc::malformed_input, what_arg) {}
        };
        struct error_code : public error
        {
            error_code(int r) : error(-r, boost::system::system_category()) {}
            error_code(int r, const char *what_arg)
                : error(-r, boost::system::system_category(), what_arg) {}
            error_code(int r, const std::string &what_arg)
                : error(-r, boost::system::system_category(), what_arg) {}
        };
    }
}

#endif // COMMON_CEPH_ERROR_CODE
